#pragma once
#ifndef MODEL_FILE_LOADER_H
#define MODEL_FILE_LOADER_H

#include <QFileInfo>
#include <QRgb>
#include <QImage>
#include <QCoreApplication>
#include <QDir>

#include "IModelFileLoader.h"
#include "assimp/Importer.hpp"
#include "assimp/scene.h"
#include "assimp/postprocess.h"

#include <execution>
#include <atomic>

#include <opencv2/opencv.hpp>

class ModelFileLoader : public IModelFileLoader
{
public:
    ModelFileLoader() = default;
    ~ModelFileLoader() = default;

    bool load(const QString& filePath) override;
    bool isLoaded() const override;
    QString lastError() const override;
    QString getFullTexturePath(const QString &texturePath) const override;

    QVector<Triangle> getTriangles() const override;
    QVector<Edge> getEdges() const override;
    QVector<QVector<Vertex>> getVertices() const override;
    QVector<QVector<unsigned int>> getVerticesIndices() const override;
    QVector<Material> getMaterials() const override;
    QVector<Light> getLights() const override;

    QVector3D getMinBounds() const override;
    QVector3D getMaxBounds() const override;

    bool hasTexture() const override;

private:
    void processNode(aiNode* node, const aiScene* scene);

    void processMesh(aiMesh* mesh, const aiScene* scene);

    void processTextures(aiMaterial *material, aiTextureType type, QString &texturePath, QByteArray &embeddedTextureData);
    void processMaterial(aiMaterial* material, Material& outMaterial);
    void fillImageWithTexture(const QVector<Material>& materials);

    void processLights(const aiScene* scene);

    // void calculateBounds();

    QVector3D convertAssimpVec3(const aiVector3D& vec) const;
    QVector3D convertAssimpNormal(const aiVector3D& normal) const;
    QVector2D convertAssimpTexCoord(const aiVector3D &texCoord) const;

private:
    bool m_loaded = false;
    QString m_lastError;
    QString m_modelDirectory;
    Assimp::Importer m_importer;
    const aiScene* m_scene = nullptr;

    QVector<QVector<Vertex>> m_vertices;
    QVector<QVector<unsigned int>> m_indices;
    QVector<Edge> m_edges;
    QVector<Triangle> m_triangles;
    QVector<Material> m_materials;
    QVector<Light> m_lights;

    QVector3D m_minBounds = QVector3D(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
    QVector3D m_maxBounds = QVector3D(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());

    QImage m_textureDiffImage, m_textureSpecImage;
};

#endif // MODEL_FILE_LOADER_H
